package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.sc.nft.dao.*;
import com.sc.nft.dto.*;
import com.sc.nft.entity.*;
import com.sc.nft.entity.req.AddAndUpdateCastExpendConfRequest;
import com.sc.nft.entity.req.AddAndUpdateCastWayConfRequest;
import com.sc.nft.entity.vo.AdminSimpleCastCollectionVO;
import com.sc.nft.entity.vo.ecology.*;
import com.sc.nft.enums.CollectionOriginalTypeEnum;
import com.sc.nft.enums.CommodityType;
import com.sc.nft.enums.EcologyExpendType;
import com.sc.nft.enums.UserEcologyCastUpperLimitDetailsTypeEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.AdminEcologyCastConfService;
import com.sc.nft.service.EcologyPointsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.web3j.abi.datatypes.Ufixed;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class AdminEcologyCastConfServiceImpl implements AdminEcologyCastConfService {

    private final DigitalCollectionProductInfoDao digitalCollectionProductInfoDao;
    private final ProductStockDao productStockDao;
    private final DigitalCollectionDao digitalCollectionDao;
    private final EcologyCastConfDao ecologyCastConfDao;
    private final EquityPropsDao equityPropsDao;
    private final EcologyCastExpendConfDao ecologyCastExpendConfDao;
    private final UserEcologyCastRecordsDao userEcologyCastRecordsDao;
    private final UserInfoDao userInfoDao;
    private final UserEcologyCastUpperLimitDao userEcologyCastUpperLimitDao;
    private final UserEcologyCastUpperLimitDetailsDao userEcologyCastUpperLimitDetailsDao;
    private final UserEcologyCastRecordsDetailsDao userEcologyCastRecordsDetailsDao;
    private final EcologyHatchConfDao ecologyHatchConfDao;
    private final UserEcologyHatchRecordsDao userEcologyHatchRecordsDao;
    private final EcologyCastWayConfDao ecologyCastWayConfDao;
    private final EcologyPointsService ecologyPointsService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addAndUpdateCastConf(EcologyCastConf ecologyCastConf, List<AddAndUpdateCastWayConfRequest> castWayList) {

        if(ObjectUtil.isNull(ecologyCastConf.getId())){
            DigitalCollectionProductInfo product = digitalCollectionProductInfoDao.getById(ecologyCastConf.getProductId());
            Assert.notNull(product,()-> new GlobalRunTimeException("商品不存在"));
            Assert.isTrue(product.getCommodityType() == CommodityType.ECOLOGY_COMMODITY,()-> new GlobalRunTimeException("商品类型不正确"));

            ProductStock productStock = productStockDao.getByProductId(product.getId());
            Assert.notNull(productStock,()-> new GlobalRunTimeException("商品不存在"));
            Assert.isTrue(productStock.getUsableCount()>0,()-> new GlobalRunTimeException("商品库存不足"));

            ecologyCastConf.setProductName(product.getFirstTitle());

            DigitalCollection collection = digitalCollectionDao.getById(product.getRelationId());
            Assert.notNull(collection,()-> new GlobalRunTimeException("商品不存在"));
            Assert.isTrue(collection.getOriginalType() == CollectionOriginalTypeEnum.MATE_UNIVERSE,()->new GlobalRunTimeException("玛特钱包的藏品不能添加到熔炼配置"));
            ecologyCastConf.setCollectionId(product.getRelationId());
            ecologyCastConf.setCollectionName(collection.getFirstTitle());
            ecologyCastConf.setSumCount(productStock.getSumCount());
            ecologyCastConf.setStatus(ObjectUtil.isNull(ecologyCastConf.getStatus()) ? Boolean.FALSE : ecologyCastConf.getStatus());
            ecologyCastConf.setSort(ObjectUtil.isNull(ecologyCastConf.getSort()) ? 0L : ecologyCastConf.getSort());
            ecologyCastConf.insert();
        }else{
            Assert.isTrue(ecologyCastConfDao.updateSortById(ecologyCastConf.getId(),ecologyCastConf.getSort()),()-> new GlobalRunTimeException("修改配置失败"));
        }
        for (AddAndUpdateCastWayConfRequest addAndUpdateCastWayConfRequest : castWayList) {
            EcologyCastWayConf ecologyCastWayConf = new EcologyCastWayConf();
            BeanUtil.copyProperties(addAndUpdateCastWayConfRequest,ecologyCastWayConf);
            ecologyCastWayConf.setEcologyCastConfId(ecologyCastConf.getId());
            ecologyCastWayConf.setWayName(addAndUpdateCastWayConfRequest.getWayName());
            ecologyCastWayConf.setStatus(addAndUpdateCastWayConfRequest.getStatus());
            if (ObjectUtil.isNull(ecologyCastWayConf.getId())) {
                ecologyCastWayConf.insert();
            }else {
                ecologyCastWayConf.updateById();
            }

            List<AddAndUpdateCastExpendConfRequest> expendList = addAndUpdateCastWayConfRequest.getExpendList();
            List<EcologyCastExpendConf> expendConfList = BeanUtil.copyToList(expendList, EcologyCastExpendConf.class);
            for (EcologyCastExpendConf ecologyCastExpendConf : expendConfList) {
                if(ecologyCastExpendConf.getExpendType() == EcologyExpendType.ECOLOGY_POINTS){//积分
                    ecologyCastExpendConf.setExpendName(EcologyExpendType.ECOLOGY_POINTS.getDescription());
                    ecologyCastExpendConf.setExpendImage(EcologyExpendType.ECOLOGY_POINTS.getImage());
                }else if (ecologyCastExpendConf.getExpendType() == EcologyExpendType.EQUITY_PROPS){//权益道具
                    EquityProps equityProps = equityPropsDao.getById(ecologyCastExpendConf.getExpendId());
                    Assert.notNull(equityProps,()-> new GlobalRunTimeException("权益道具不存在"));
                    ecologyCastExpendConf.setExpendName(equityProps.getFirstTitle());
                    ecologyCastExpendConf.setExpendImage(equityProps.getCreationContent());
                }else {//权益道具
                    EcologyPoints ecologyPoints = ecologyPointsService.getById(ecologyCastExpendConf.getExpendId());
                    Assert.notNull(ecologyPoints, () -> new GlobalRunTimeException("选择积分不存在"));
                    ecologyCastExpendConf.setExpendName(ecologyPoints.getPointsName());
                    ecologyCastExpendConf.setExpendImage(ecologyPoints.getPointsImage());
                }
                ecologyCastExpendConf.setEcologyCastConfId(ecologyCastConf.getId());
                ecologyCastExpendConf.setEcologyCastWayConfId(ecologyCastWayConf.getId());
                if(ObjectUtil.isNull(ecologyCastExpendConf.getId())){
                    ecologyCastExpendConf.insert();
                }else{
                    EcologyCastExpendConf getOne = ecologyCastExpendConfDao.getOneByIdAndEcologyCastConfId(ecologyCastExpendConf.getId(), ecologyCastExpendConf.getEcologyCastConfId());
                    Assert.notNull(getOne,()-> new GlobalRunTimeException("生态铸造消耗配置不存在"));

                    EcologyCastConf getById = ecologyCastConfDao.getById(ecologyCastExpendConf.getEcologyCastConfId());
                    Assert.isFalse(getById.getStatus(),()-> new GlobalRunTimeException("生态铸造配置已经启用，不可修改"));

                    ecologyCastExpendConf.updateById();
                }
            }
        }

    }

    @Override
    public Page<AdminGetPageCastConfVO> getPageCastConf(String collectionName, Integer pageNo, Integer pageSize) {
        return ecologyCastConfDao.getPageCastConf(collectionName,pageNo,pageSize);
    }

    @Override
    public AdminCastConfDetailsVO getCastConfDetails(Long id) {
        EcologyCastConf ecologyCastConf = ecologyCastConfDao.getById(id);
        Assert.notNull(ecologyCastConf,()-> new GlobalRunTimeException("生态铸造配置不存在"));

        AdminCastConfDetailsVO adminCastConfDetailsVO = BeanUtil.copyProperties(ecologyCastConf, AdminCastConfDetailsVO.class);
        List<EcologyCastWayConf> ecologyCastWayConfList = ecologyCastWayConfDao.getListByEcologyCastConfId(ecologyCastConf.getId());
        adminCastConfDetailsVO.setCastWayList(BeanUtil.copyToList(ecologyCastWayConfList, AdminCastConfWayDetailsVO.class));
        List<EcologyCastExpendConf> expendConfList = ecologyCastExpendConfDao.getListByEcologyCastConfId(ecologyCastConf.getId());
        Map<Long, List<EcologyCastExpendConf>> wayMap = expendConfList.stream().collect(Collectors.groupingBy(EcologyCastExpendConf::getEcologyCastWayConfId));
        for (AdminCastConfWayDetailsVO adminCastConfWayDetailsVO : adminCastConfDetailsVO.getCastWayList()) {
            if (wayMap.containsKey(adminCastConfWayDetailsVO.getId())) {
                List<EcologyCastExpendConf> ecologyCastExpendList = wayMap.get(adminCastConfWayDetailsVO.getId());
                adminCastConfWayDetailsVO.setExpendList(BeanUtil.copyToList(ecologyCastExpendList, AdminCastConfExpendDetailsVO.class));
            }
        }
        return adminCastConfDetailsVO;
    }

    @Override
    public void delExpendById(Long id) {
        EcologyCastExpendConf ecologyCastExpendConf = ecologyCastExpendConfDao.getById(id);
        Assert.notNull(ecologyCastExpendConf,()-> new GlobalRunTimeException("生态铸造消耗配置不存在"));

        EcologyCastConf ecologyCastConf = ecologyCastConfDao.getById(ecologyCastExpendConf.getEcologyCastConfId());
        Assert.notNull(ecologyCastConf,()-> new GlobalRunTimeException("生态铸造配置不存在"));
        Assert.isFalse(ecologyCastConf.getStatus(),()-> new GlobalRunTimeException("生态铸造配置已经启用，不可修改"));

        Assert.isTrue(ecologyCastExpendConfDao.delExpendById(id),()-> new GlobalRunTimeException("删除生态铸造消耗配置更新失败"));
    }

    @Override
    public void updateCastConfStatusgById(Long id, Boolean status) {
        EcologyCastConf ecologyCastConf = ecologyCastConfDao.getById(id);
        Assert.notNull(ecologyCastConf,()-> new GlobalRunTimeException("生态铸造配置不存在"));
        if (status) {
            //开启需要判断
            Assert.isTrue(ecologyCastWayConfDao.countOpenByConfId(id) > 0,()-> new GlobalRunTimeException("请先开启铸造方式"));
        }
        Assert.isTrue(ecologyCastConfDao.updateStatusById(id,status),()-> new GlobalRunTimeException("生态铸造配置状态更新失败"));
    }

    @Override
    public void updateCastConfSortById(Long id, Long sort) {
        EcologyCastConf ecologyCastConf = ecologyCastConfDao.getById(id);
        Assert.notNull(ecologyCastConf,()-> new GlobalRunTimeException("生态铸造配置不存在"));

        Assert.isTrue(ecologyCastConfDao.updateSortById(id,sort),()-> new GlobalRunTimeException("生态铸造配置排序更新失败"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delCastConfById(Long id) {
        EcologyCastConf ecologyCastConf = ecologyCastConfDao.getById(id);
        Assert.notNull(ecologyCastConf,()-> new GlobalRunTimeException("生态铸造配置不存在"));
        Assert.isFalse(ecologyCastConf.getStatus(),()-> new GlobalRunTimeException("生态铸造配置已经启用，不可删除"));

        Assert.isTrue(ecologyCastConfDao.delCastConfById(id),()-> new GlobalRunTimeException("删除生态铸造配置更新失败"));
        Assert.isTrue(ecologyCastWayConfDao.delByEcologyCastConfId(id),()-> new GlobalRunTimeException("删除生态铸造方式配置更新失败"));
        Assert.isTrue(ecologyCastExpendConfDao.delByEcologyCastConfId(id),()-> new GlobalRunTimeException("删除生态铸造消耗配置更新失败"));
    }

    @Override
    public Page<AdminEcologyCastUserRecordsVO> getPageUserRecordsRecords(String collectionName, String userTel, String startTime, String endTime, Integer pageNo, Integer pageSize) {
        Long userId = null;
        if (StrUtil.isNotBlank(userTel)){
            UserInfo userInfo = userInfoDao.getOneByUserTel(userTel);
            if (ObjectUtil.isNull(userInfo)){
                return new Page<>(pageNo,pageSize);
            }
            userId = userInfo.getId();
        }
        Long collectionId = null;
        if (StrUtil.isNotBlank(collectionName)){
            DigitalCollection collection = digitalCollectionDao.getByTitle(collectionName);
            if (ObjectUtil.isNull(collection)){
                return new Page<>(pageNo,pageSize);
            }
            collectionId = collection.getId();
        }
        return userEcologyCastRecordsDao.getPageUserRecordsRecords(collectionId,userId,startTime,endTime,pageNo,pageSize);
    }

    @Override
    public List<AdminEcologyCastUserRecordsVO> getPageUserRecordsExport(String collectionName, String userTel, String startTime, String endTime) {
        Long userId = null;
        if (StrUtil.isNotBlank(userTel)){
            UserInfo userInfo = userInfoDao.getOneByUserTel(userTel);
            if (ObjectUtil.isNull(userInfo)){
                return new ArrayList<>();
            }
            userId = userInfo.getId();
        }
        Long collectionId = null;
        if (StrUtil.isNotBlank(collectionName)){
            DigitalCollection collection = digitalCollectionDao.getByTitle(collectionName);
            if (ObjectUtil.isNull(collection)){
                return new ArrayList<>();
            }
            collectionId = collection.getId();
        }

        return userEcologyCastRecordsDao.getPageUserRecordsExport(collectionId,userId,startTime,endTime);
    }

    @Override
    public List<AdminUserEcologyCastUpperLimitDetailsVO> userEcologyCastUpperLimitDetails(String userTel) {
        return userEcologyCastUpperLimitDao.userEcologyCastUpperLimitDetails(userTel);
    }

    @Override
    public Page<AdminUserEcologyCastUpperLimitPageVO> userEcologyCastUpperLimitPage(Long userId, Long collectionId, Date beginTime, Date endTime, Integer pageNo, Integer pageSize) {
        return userEcologyCastUpperLimitDetailsDao.getUserEcologyCastUpperLimitPage(userId,collectionId,beginTime,endTime,pageNo,pageSize);
    }

    @Override
    public Page<AdminSimpleCastCollectionVO> getSimplePage(Integer pageNo, Integer pageSize) {
        return ecologyCastConfDao.getSimplePage(pageNo,pageSize);
    }

    @Override
    public void initCastUpperLimit() {

        List<EcologyHatchConf> hatchConfList = ecologyHatchConfDao.getListByStatus();

        for (EcologyHatchConf ecologyHatchConf : hatchConfList) {

            //铸造这个藏品的所有用户和数量
            List<UserHatchCountDTO> userHatchCountDTOList = userEcologyHatchRecordsDao.getListByGroupUserIdAndCollectionId(ecologyHatchConf.getCollectionId());
            int i = 0;
            for (UserHatchCountDTO userHatchCountDTO : userHatchCountDTOList) {
                i++;

                //这个用户 铸造了多少份这个藏品
                Integer castCount = userEcologyCastRecordsDetailsDao.getCountByUserIdAndCollectionId(userHatchCountDTO.getUserId(), ecologyHatchConf.getCollectionId());

                Long userId = userHatchCountDTO.getUserId();

                //这个用户 这个藏品可以铸造的总量
                int sumCount = userHatchCountDTO.getHatchCount().intValue() * ecologyHatchConf.getAddCastCount();

                int usableCount = sumCount - castCount.intValue() >= 0 ? sumCount - castCount.intValue() : 0;

                UserEcologyCastUpperLimit userEcologyCastUpperLimit = new UserEcologyCastUpperLimit();
                userEcologyCastUpperLimit.setUserId(userId);
                userEcologyCastUpperLimit.setCollectionId(ecologyHatchConf.getCollectionId());
                userEcologyCastUpperLimit.setUsableCount(usableCount);
                userEcologyCastUpperLimit.insert();


                UserEcologyCastUpperLimitDetails userEcologyCastUpperLimitDetails = new UserEcologyCastUpperLimitDetails();
                userEcologyCastUpperLimitDetails.setUserId(userId);
                userEcologyCastUpperLimitDetails.setCollectionId(ecologyHatchConf.getCollectionId());
                userEcologyCastUpperLimitDetails.setUserRecordsId(0L);

                UserEcologyCastUpperLimitDetailsTypeEnum type = castCount == 0 ? UserEcologyCastUpperLimitDetailsTypeEnum.SMELTING : UserEcologyCastUpperLimitDetailsTypeEnum.CAST;
                userEcologyCastUpperLimitDetails.setType(type);
                userEcologyCastUpperLimitDetails.setTypeName(type.getDescription());
                userEcologyCastUpperLimitDetails.setUseCount(castCount);
                userEcologyCastUpperLimitDetails.setBeforeCount(sumCount);
                userEcologyCastUpperLimitDetails.setAfterCount(usableCount);
                userEcologyCastUpperLimitDetails.setIsAdd(type.getIsAdd());
                userEcologyCastUpperLimitDetails.insert();

                log.info("藏品名称:{},剩余数量:{}",ecologyHatchConf.getCollectionName(),userHatchCountDTOList.size()-i);
            }
        }
    }
}
